﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Imaging;
using AForge.Imaging.Filters;
using AForge;
using AForge.Imaging;
using AForge.Math.Geometry;
using System.Drawing;

namespace BulkImageSplitter
{
    /// <summary>
    /// A utility to split compound images into parts based on a background filter.
    /// </summary>
    public class Splitter
    {
        /// <summary>
        /// The directory to write the output files to.
        /// </summary>
        public string OutputDirectory { get; set; }

        /// <summary>
        /// The background filter.
        /// </summary>
        public ColorFiltering BackgroundFilter { get; set; }

        /// <summary>
        /// The minimum acceptable size for detected images.
        /// </summary>
        public Size MinimumSize { get; set; }

        Action<string> _logAction;

        public Splitter(Action<string> logAction)
        {
            _logAction = logAction;
        }

        public void SplitImage(Bitmap bitmap, string file)
        {
            // lock image
            BitmapData bitmapData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadWrite, 
                bitmap.PixelFormat);

            // step 1 - filter background
            BackgroundFilter.FillOutsideRange = false;
            BackgroundFilter.ApplyInPlace(bitmapData);

            // step 2 - locating objects
            BlobCounter blobCounter = new BlobCounter();

            blobCounter.FilterBlobs = true;
            blobCounter.MinHeight = MinimumSize.Height;
            blobCounter.MinWidth = MinimumSize.Width;

            blobCounter.ProcessImage(bitmapData);
            Blob[] blobs = blobCounter.GetObjectsInformation();
            bitmap.UnlockBits(bitmapData);

            // step 3 - save out all matching rectangles
            SimpleShapeChecker shapeChecker = new SimpleShapeChecker();

            int exportCount = 1;

            // Reload the bitmap without the background filtering
            var originalBitmap = (Bitmap)Bitmap.FromFile(file);

            foreach (Blob blob in blobs)
            {
                List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blob);

                DoublePoint center;
                double radius;

                // is circle ?
                if (!shapeChecker.IsCircle(edgePoints, out center, out radius))
                {
                    List<IntPoint> corners;

                    // is triangle or quadrilateral
                    if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
                    {
                        // get sub-type
                        PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);

                        if (subType == PolygonSubType.Rectangle ||
                            subType == PolygonSubType.Square ||
                            subType == PolygonSubType.Unknown && corners.Count == 4)
                        {
                            var width = blob.Rectangle.Width;
                            var height = blob.Rectangle.Height;

                            // Paint the sub-image onto a new bitmap
                            Bitmap child = new Bitmap(width, height);
                            Graphics graphics = Graphics.FromImage(child);
                            var destRectangle = new System.Drawing.Rectangle(0, 0, width, height);
                            graphics.DrawImage(originalBitmap, destRectangle, blob.Rectangle, GraphicsUnit.Pixel);

                            var fileName = System.IO.Path.GetFileNameWithoutExtension(file);
                            var extension = System.IO.Path.GetExtension(file);
                            var childFile = string.Format("{0}-{1}{2}", fileName, exportCount, extension);

                            _logAction(string.Format("Save sub-image: '{0}'", childFile));
                            child.Save(System.IO.Path.Combine(OutputDirectory, childFile));

                            exportCount++;
                        }
                    }
                }
            }
        }
    }
}
